//------------------------------------------------------------------------------
//SFWK Framework
//Copyright (C) 2011 SQLI

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel;
using System.Transactions;
using SFWK.Core;
using SFWK.Core.Error;
using SFWK.Core.Security;

namespace SFWK.Services
{
    [ServiceBehavior(TransactionAutoCompleteOnSessionClose = true, TransactionIsolationLevel = IsolationLevel.ReadCommitted, TransactionTimeout = "00:20:00")]
    public abstract class BaseService
    {
        #region Protected Methods
        protected void Log(Exception ex)
        {
            LogHelper.Log(ex, ELogSeverity.Information);
        }

        protected void Log(Exception ex, object context)
        {
            LogHelper.Log(context, ex, ELogSeverity.Information);
        }
        #endregion


        #region Protected Error Methods
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="TDetail"></typeparam>
        ///// <param name="ex"></param>
        ///// <param name="parameters"></param>
        //protected virtual void OnError<TDetail>(Exception ex, string[] parameters) where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    if ((ex.InnerException != null) && (ex.InnerException is OperationException<TDetail>))
        //    {
        //        OperationException<TDetail>.ThrowException(ex.InnerException, parameters);
        //    }
        //    else
        //    {
        //        Log(ex);
        //        OperationException<TDetail>.ThrowException(ex, parameters);
        //    }
        //}
        //protected virtual void OnError<TDetail>(Exception ex, string parameter) where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    Log(ex);
        //    OperationException<TDetail>.ThrowException(ex, new string[] { parameter });
        //}
        //protected virtual void OnError<TDetail>(string parameter) where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    OperationException<TDetail>.ThrowException(new string[] { parameter });
        //}

        /// <summary>
        /// Handle errors:
        ///     Log exception if not null
        ///     Re-Throw business exception with clear error message
        /// </summary>
        /// <typeparam name="TDetail">Business error type</typeparam>
        /// <typeparam name="TEntity">Type of entity requested during error occurence</typeparam>
        /// <param name="ex">Caught excption</param>
        /// <param name="context">Context during error ocurence</param>
        protected virtual void OnError<TDetail,TEntity>(Exception ex, object context) where TDetail : SFWK.Core.SFWKError, new()
        {
            if (ex != null)
            {
                if ((ex.InnerException != null) && (ex.InnerException is OperationException<TDetail>))
                {
                    if (((OperationException<TDetail>)ex.InnerException).Detail.Parameters != null)
                    {
                        List<string> param = ((OperationException<TDetail>)ex.InnerException).Detail.Parameters;
                        OperationException<TDetail>.ThrowException(ex.InnerException, param.ToArray());
                    }
                    else
                    {
                        OperationException<TDetail>.ThrowException(ex.InnerException, new string[] { (typeof(TEntity)).Name });
                    }
                }
                else if ((ex != null) && (ex is OperationException<TDetail>))
                {
                    if (((OperationException<TDetail>)ex).Detail.Parameters != null)
                    {
                        List<string> param = ((OperationException<TDetail>)ex).Detail.Parameters;
                        OperationException<TDetail>.ThrowException(ex, param.ToArray());
                    }
                    else
                    {
                        OperationException<TDetail>.ThrowException(ex, new string[] { (typeof(TEntity)).Name });
                    }
                }
                else
                {
                    Log(ex, context);
                    OperationException<TDetail>.ThrowException(ex, new string[] { (typeof(TEntity)).Name });
                }
            }
            OperationException<TDetail>.ThrowException(new string[] { (typeof(TEntity)).Name });
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="TDetail"></typeparam>
        ///// <typeparam name="TEntity"></typeparam>
        ///// <param name="ex"></param>
        ///// <param name="entity"></param>
        //protected virtual void OnError<TDetail, TEntity>(Exception ex, TEntity entity) where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    if (ex != null)
        //    {
        //        if ((ex.InnerException != null) && (ex.InnerException is OperationException<TDetail>))
        //        {
        //            OperationException<TDetail>.ThrowException(ex.InnerException, new string[] { (typeof(TEntity)).Name });
        //        }
        //        else
        //        {
        //            if (entity != null)
        //                Log(ex, entity);
        //            else
        //                Log(ex);
        //            OperationException<TDetail>.ThrowException(ex, new string[] { (typeof(TEntity)).Name });
        //        }
        //    }
        //    else
        //    {
        //        OperationException<TDetail>.ThrowException(new string[] { (typeof(TEntity)).Name });
        //    }
        //}
        //protected virtual void OnError<TDetail, TEntity>() where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    OperationException<TDetail>.ThrowException(new string[] { (typeof(TEntity)).Name });
        //}
        //protected virtual void OnError<TDetail, TEntity, TContext>(TContext context) where TDetail : SFWK.Core.SFWKError, new()
        //{
        //    OperationException<TDetail>.ThrowException(new string[] { (typeof(TEntity)).Name });
        //}
        #endregion

        #region protected security check
        /// <summary>
        /// Checks contextual permission for a specific entity or Id, throws a UnauthorizedOperation exception if not allowed
        /// </summary>
        /// <typeparam name="TFact">Security operation to be check</typeparam>
        /// <param name="context">Optional context key or entity to check security on</param>
        protected virtual void OnCheckPermission<TFact>(object context) where TFact : SFWKOperation, new()
        {
            if (context != null)
            {
                if (!new TFact().HasPermissionForContext(context))
                    OperationException<UnauthorizedOperation>.ThrowException(new string[]{(typeof(TFact)).DeclaringType.Name + " / " + typeof(TFact).Name});
            }
            else if(! new TFact().HasPermission())
                OperationException<UnauthorizedOperation>.ThrowException(new string[] { (typeof(TFact)).DeclaringType.Name + " / " + typeof(TFact).Name });
        }

        #endregion
    }
}
